#!/usr/bin/python
import sys, os, time
def addpath(s): os.path.exists(s) and sys.path.insert(0, s)
addpath('/ddb/lib')
#################


# TODO: use werkzeug/jinja2
# TODO: task['parent']
# TODO: task['name']
# TODO: task['binary']
# TODO: task['stdin']

MONGO_SERVER = 'h1'
#MONGO_SERVER = 'localhost'

import json, re
from webob import Request#, Response
import pymongo
from pymongo.connection import Connection
from pymongo.objectid import ObjectId
#from pymongo.dbref import DBRef

DB = Connection(MONGO_SERVER, 27017).tito


# TODO: move deansi to own module
COLORS = ['black', 'maroon', 'green', 'olive', 'navy', 'purple', 'teal', 'silver']
BRIGHT_COLORS = ['gray', 'red', 'lime', 'yellow', 'blue', 'fuchsia', 'cyan', 'white']
RE_DEANSI = re.compile('\x1B\[(\d+);3(\d+);4(\d+)m')
def deansi(s):
    def replacer(m):
        bright, fg, bg = map(int,m.groups())
        if bright:
            return '<span style="color:%s;background-color:%s">' % (BRIGHT_COLORS[fg], COLORS[bg])
        else:
            return '<span style="color:%s;background-color:%s">' % (COLORS[fg], COLORS[bg])
    return RE_DEANSI.sub(replacer, s)
#RE_DEANSI = re.compile('\x1B\[(\d+);3(\d+);4(\d+)m([^\x1B]*)')
#def deansi(s):
#    def replacer(m):
#        intensity, fg, bg, txt = m.groups()
#        intensity, fg, bg = map(int, [intensity, fg, bg])
#       if txt:
#            if intensity:
#                return '<span style="color:%s;background-color:%s">%s</span>' % (INTCOLORS[fg], COLORS[bg], txt)
#            else:
#                return '<span style="color:%s;background-color:%s">%s</span>' % (COLORS[fg], COLORS[bg], txt)
#        return ''
#    return RE_DEANSI.sub(replacer, s)


def dict_filter(d, keys):
    rc = {}
    for k in keys:
        if k in d:
            rc[k] = d[k]
    return rc

def tito_wsgi_app(environ, start_response):
    def answer_json(s):
        #return Response(str(s))(environ, start_response)
        start_response('200 OK', [('Content-Type',  'application/json'),
                                  ('Pragma',        'no-cache'),
                                  ('Cache-Control', 'no-store, no-cache, max-age=0, must-revalidate'),
                                  ('Refresh',       '-1')])
        return [str(s)]

    def answer_html(s):
        #return Response(str(s))(environ, start_response)
        start_response('200 OK', [('Content-Type',  'text/html')])
        return [str(s)]

    req = Request(environ)

    start = time.time()
    print start, req.path_info,

    if req.path_info=='/':
        return answer(environ)

#    if req.path_info=='/monitor':
#        sysinfos = map(str, DB.monitor.find())
#       o = '<hr>'.join(sysinfos)
#        return answer(o)

#    if req.path_info=='/machines.json':
#        l = []
#        for machine in DB.monitor.distinct("machine_id"):
#            last_sysinfo = DB.monitor.find({"machine_id":machine}).sort('time', -1).limit(1).next()
#            l.append( dict_filter(last_sysinfo, ['machine_id', 'hostname', 'time']) );
#        return answer(json.write( {'machines': l} ))

    if req.path_info=='/tasks.json':
        if 'machine_ids[]' in req.params: # and (req.params.get('cmd','')!='' or req.params.get('binary','')!=''):
            t = dict_filter(req.params, ['name', 'cwd', 'cmd', 'binary'])
            t['status'] = 'new'
            for machine in req.params.getall('machine_ids[]'):
                t['machine_id'] = machine
                #print t
                DB.tasks.save(t.copy())

        if 'del' in req.params:
            oid = ObjectId(req.params['del'])
            DB.tasks.remove(oid)
            DB.progress.remove({'task_id' : str(oid)})

        rc = {}
        rc['tasks'] = []
        for task in DB.tasks.find().sort('_id', -1):
            task['_id'] = str(task['_id'])
            #task['_id'] = str(oid)

            stdout = ''
            stderr = ''
            task['progress'] = []
            # {$natural:-1}  newest to oldest
            for event in DB.progress.find({'task_id' : task['_id']}).sort('$natural', -1).limit(50):
                #del event['task']
                #del event['_id']
                #task['progress'].append(event)
                #    stdout = event['stdout'] + stdout
                #if len(stderr)<2000:
                #    stderr = event['stderr'] + stderr
                stdout = event['stdout'] + stdout
                stderr = event['stderr'] + stderr
                if len(stdout) + len(stderr)>4096:
                    break

            stdout = deansi(stdout)
            stderr = deansi(stderr)

            task['stdout'] = '\n'.join(stdout.split('\n')[-10:])
            task['stderr'] = '\n'.join(stderr.split('\n')[-10:])
            #rc['tasks'][task['_id']] = task
            rc['tasks'].append(task)

        # list of machines from monitor
        rc['machines'] = []
        rc['history'] = {}
        latest_sysinfo = None
        for machine in DB.monitor.distinct("machine_id"):
            counter = 0
            # {$natural:-1}  newest to oldest
            for sysinfo in DB.monitor.find({"machine_id":machine}).sort('$natural', -1):
                counter = counter + 1
                if counter == 1:
                    latest_sysinfo = sysinfo
                    d = dict_filter(sysinfo, ['machine_id', 'hostname', 'time',
                        'la1', 'la5', 'la10', 'uptime', 'version', 'rproc', 'nproc', 'memory'])
                    d['age'] = int(time.time() - float(d['time']))
                    rc['machines'].append( d );
                    rc['history'][ sysinfo['machine_id'] ] = []
                rc['history'][ sysinfo['machine_id'] ].append({
                    'time':  sysinfo['time'],
                    'la5':   sysinfo['la5'],
                    'nproc': sysinfo['nproc']
                })
                if sysinfo['time'] < latest_sysinfo['time'] - 3*3600:
                    break
#        rc['monitor'] = []
        print time.time() - start
        return answer_json( json.write( rc ) )


#    if req.path_info=='/progress.json':
#        return answer('{}')


    if req.path_info=='/tasks':
        return answer_html(file('/ddb/website/tito/tasks.html').read())
